import pandas as pd
import numpy as np
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv1D, MaxPooling1D, GRU, Dense, Dropout
from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau
import os
import matplotlib.pyplot as plt
import joblib

# 读取数据
try:
    data = pd.read_excel('datasets/guangfu2019.xlsx')
except FileNotFoundError:
    print("未找到数据集文件，请检查文件路径。")
    exit(1)

# 数据清洗：处理缺失值
data = data.dropna()

# 分离特征和目标变量，排除时间列
features = data.drop(['时间', '实际发电功率(mw)'], axis=1).values
target = data['实际发电功率(mw)'].values

# 数据归一化
scaler_features = MinMaxScaler()
scaler_target = MinMaxScaler()
features = scaler_features.fit_transform(features)
target = scaler_target.fit_transform(target.reshape(-1, 1))

# 准备训练数据
sequence_length = 10
X = []
y = []
for i in range(len(features) - sequence_length):
    X.append(features[i:i+sequence_length])
    y.append(target[i+sequence_length])
X = np.array(X)
y = np.array(y)

# 数据集划分：训练集和验证集
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)

# 构建 CNN - GRU 模型
model = Sequential()
model.add(Conv1D(filters=128, kernel_size=3, activation='relu', input_shape=(sequence_length, X.shape[2])))
model.add(MaxPooling1D(pool_size=2))
model.add(Dropout(0.2))
model.add(GRU(100, activation='relu', return_sequences=False))
model.add(Dropout(0.2))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')

# 定义 EarlyStopping 回调
early_stopping = EarlyStopping(monitor='val_loss', patience=20, restore_best_weights=True)

# 定义学习率调度器
reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=10, min_lr=0.00001)

# 训练模型并记录训练历史
history = model.fit(X_train, y_train, epochs=100, batch_size=64,
                    validation_data=(X_val, y_val),
                    callbacks=[early_stopping, reduce_lr], verbose=1)

# 创建保存模型的文件夹
if not os.path.exists('model'):
    os.makedirs('model')

# 保存模型
model.save('model/cnn_gru_model.h5')

# 保存特征和目标的归一化器
joblib.dump(scaler_features, 'model/scaler_features.pkl')
joblib.dump(scaler_target, 'model/scaler_target.pkl')

# 绘制损失函数迭代图
plt.figure(figsize=(12, 6))
plt.plot(history.history['loss'], color='blue', linestyle='-', label='Training Loss')
plt.plot(history.history['val_loss'], color='orange', linestyle='-', label='Validation Loss')
plt.title('Model Loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(loc='upper right')
plt.grid(True)
plt.savefig('model/loss_plot.png')
plt.show()

# 进行预测
predictions = model.predict(X_val)
predictions = scaler_target.inverse_transform(predictions)
true_values = scaler_target.inverse_transform(y_val)

# 生成 x 轴数据，表示第几条数据
x_axis = np.arange(len(true_values))

# 绘制预测值和真实值的折线图对比图
plt.figure(figsize=(12, 6))
plt.plot(x_axis, true_values, color='blue', linestyle='-', label='True Values')
plt.plot(x_axis, predictions, color='red', linestyle='--', label='Predictions')
plt.title('True Values vs Predictions')
plt.ylabel('Actual Power Generation (MW)')
plt.xlabel('Row Number in Excel')
plt.legend(loc='upper right')
plt.grid(True)
plt.savefig('model/prediction_comparison.png')
plt.show()